﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SharpGL.SceneGraph;
using SharpGL;
using GestureSaver;
using Microsoft.Kinect;
using System.IO;

namespace GestureVisualizer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        bool capturing;

        string snapshotPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\Snapshots\";

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            TakeInput();
            capturing = true;

            if (capturing)
            {
                if (!Directory.Exists(snapshotPath))
                {
                    Directory.CreateDirectory(snapshotPath);
                }
            }

            InitializeComponent();
        }

        Gesture gesture;

        private string AskFileName()
        {
            System.Windows.Forms.OpenFileDialog openFileDialog1 = new System.Windows.Forms.OpenFileDialog();

            openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\DB";
            openFileDialog1.Filter = "txt files (*.txt)|*.txt";
            openFileDialog1.FilterIndex = 0;
            openFileDialog1.RestoreDirectory = true;

            string rVal = string.Empty;

            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                rVal = openFileDialog1.FileName;
            }

            return rVal;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            
        }

        /// <summary>
        /// Handles the OpenGLInitialized event of the openGLControl1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="args">The <see cref="SharpGL.SceneGraph.OpenGLEventArgs"/> instance containing the event data.</param>
        private void openGLControl_OpenGLInitialized(object sender, OpenGLEventArgs args)
        {
            //  TODO: Initialise OpenGL here.

            //  Get the OpenGL object.
            OpenGL gl = openGLControl.OpenGL;
                        
            //  Set the clear color.
            gl.ClearColor(1, 1, 1, 0);

            gl.LineWidth(3);
            gl.PointSize(10.0f);

        }

        int i = 0;
        OpenGL gl;        

        double cameraY = -0.2;
        double cameraZ = -1;

        double lookatY = -0.2;

        /// <summary>
        /// Handles the OpenGLDraw event of the openGLControl1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="args">The <see cref="SharpGL.SceneGraph.OpenGLEventArgs"/> instance containing the event data.</param>
        private void openGLControl_OpenGLDraw(object sender, OpenGLEventArgs args)
        {
            //  Get the OpenGL object.
            gl = openGLControl.OpenGL;

            //  Clear the color and depth buffer.
            gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);

            //  Load the identity matrix.
            gl.LoadIdentity();

            //  Use the 'look at' helper function to position and aim the camera.
            gl.LookAt(0, cameraY, cameraZ, 0, lookatY, 1000, 0, 1, 0);

            i++;

            if (i == gesture.SkeletonCount)
            {
                i = 0;
                capturing = false;
            }

            gl.Enable(OpenGL.GL_POINT_SMOOTH);
            gl.Enable(OpenGL.GL_LINE_SMOOTH);

            gl.Color(0.0f, 1.0f, 0.0f);
            ConnectJoints(gesture[i][JointType.FootRight],
                          gesture[i][JointType.AnkleRight],
                          gesture[i][JointType.KneeRight],
                          gesture[i][JointType.HipRight],
                          gesture[i][JointType.HipCenter],
                          gesture[i][JointType.Spine],
                          gesture[i][JointType.ShoulderCenter],
                          gesture[i][JointType.ShoulderRight],
                          gesture[i][JointType.ElbowRight],
                          gesture[i][JointType.WristRight],
                          gesture[i][JointType.HandRight]);

            ConnectJoints(gesture[i][JointType.FootLeft],
                          gesture[i][JointType.AnkleLeft],
                          gesture[i][JointType.KneeLeft],
                          gesture[i][JointType.HipLeft],
                          gesture[i][JointType.HipCenter],
                          gesture[i][JointType.Spine],
                          gesture[i][JointType.ShoulderCenter],
                          gesture[i][JointType.ShoulderLeft],
                          gesture[i][JointType.ElbowLeft],
                          gesture[i][JointType.WristLeft],
                          gesture[i][JointType.HandLeft]);

            ConnectJoints(gesture[i][JointType.ShoulderCenter],
                          gesture[i][JointType.Head]);  

            foreach (JointType j in Enum.GetValues(typeof(JointType)))
            {
                gl.Color(1.0f, 0.0f, 0.0f);
               
                gl.Begin(OpenGL.GL_POINTS);
                gl.Vertex(gesture[i][j].Position.X, gesture[i][j].Position.Y, 0);
                gl.End();
            }

            // Swap buffers
            gl.Flush();

            if (capturing)
            {
                string fileName = "Snapshot_";

                int id = 1;
                while (File.Exists(snapshotPath + fileName + id.ToString("D3") + ".png"))
                {
                    id++;
                }

                string fullFileName = snapshotPath + fileName + id.ToString("D3") + ".png";

                SaveToFile(openGLControl, fullFileName);
            }
        }

        private void ConnectJoints(params MJoint[] joints)
        {
            gl.Begin(OpenGL.GL_LINES);

            for (int i = 0; i < joints.Length - 1; i++)
            {
                gl.Vertex(joints[i].Position.X, joints[i].Position.Y, 0);
                gl.Vertex(joints[i+1].Position.X, joints[i+1].Position.Y, 0);
            }

            gl.End();
        }

        

        /// <summary>
        /// Handles the Resized event of the openGLControl1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="args">The <see cref="SharpGL.SceneGraph.OpenGLEventArgs"/> instance containing the event data.</param>
        private void openGLControl_Resized(object sender, OpenGLEventArgs args)
        {
            //  TODO: Set the projection matrix here.

            //  Get the OpenGL object.
            OpenGL gl = openGLControl.OpenGL;

            //  Set the projection matrix.
            gl.MatrixMode(OpenGL.GL_PROJECTION);

            //  Load the identity.
            gl.LoadIdentity();

            //  Create a perspective transformation.
            gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0);

            //  Set the modelview matrix.
            gl.MatrixMode(OpenGL.GL_MODELVIEW);
        }

        private void TakeInput()
        {
            string fileName = AskFileName();
            if (fileName != string.Empty)
            {
                i = 0;
                gesture = new Gesture(fileName);
                capturing = true;
            }
        }

        private void Window_MouseDown(object sender, MouseButtonEventArgs e)
        {
            TakeInput();
        }

        private void SaveToFile(UIElement source, string fileName)
        {
            double w = source.RenderSize.Width;
            double h = source.RenderSize.Height;

            RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)w, (int)h, 96, 96, PixelFormats.Default);
            VisualBrush sourceBrush = new VisualBrush(source);

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            using (drawingContext)
            {
                drawingContext.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0), new System.Windows.Point(w, h)));
            }
            renderTarget.Render(drawingVisual);

            PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
            pngEncoder.Frames.Add(BitmapFrame.Create(renderTarget));

            pngEncoder.Save(new FileStream(fileName, FileMode.Create));
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {           
            if (e.Key == Key.Up)
            {
                cameraY -= 0.1;
                lookatY -= 0.1;
            }
            else if (e.Key == Key.Down)
            {
                cameraY += 0.1;
                lookatY += 0.1;
            }
            else if (e.Key == Key.Left)
            {
                cameraZ -= 0.1;
            }
            else if (e.Key == Key.Right)
            {
                cameraZ += 0.1;
            }
            else if (e.Key == Key.Q)
            {
                gesture = gesture.GetSubset(1, gesture.SkeletonCount - 1);
                gesture.SaveToFile(gesture.inputFileName);

                i = 0;
                capturing = true;
            }
            else if (e.Key == Key.R)
            {
                gesture = gesture.GetSubset(0, gesture.SkeletonCount - 2);
                gesture.SaveToFile(gesture.inputFileName);

                i = 0;
                capturing = true;
            }
        }
    }
}
